package nio.groupchat;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

/**
 * 聊天室-服务端
 *
 * @author jack.wu
 * @version 1.0
 * @date 2020-05-14
 */
public class GroupCharServer {


    private Selector selector;
    private ServerSocketChannel serverSocketChannel;
    private final int PORT = 6667;

    public GroupCharServer() {
        try {
            selector = Selector.open();
            serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.bind(new InetSocketAddress(PORT));
            serverSocketChannel.configureBlocking(false);
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * 监听方法
     */
    private void listen() {

        try {
            while (true) {
                int count = selector.select(2000);
                if (count > 0) {
                    // 如果有相应的事件发生
                    Set<SelectionKey> selectionKeys = selector.selectedKeys();
                    // 处理相关事件
                    processEvent(selectionKeys);
                } else {
                    System.out.println("等待~~~~");
                }

            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {

        }

    }


    /**
     * 处理事件
     *
     * @param selectionKeys
     */
    private void processEvent(Set<SelectionKey> selectionKeys) throws IOException {

        Iterator<SelectionKey> keyIterator = selectionKeys.iterator();

        while (keyIterator.hasNext()) {
            SelectionKey selectionKey = keyIterator.next();
            if (selectionKey.isAcceptable()) {
                SocketChannel socketChannel = serverSocketChannel.accept();
                socketChannel.configureBlocking(false);
                socketChannel.register(selector, SelectionKey.OP_READ);
                System.out.println(socketChannel.getRemoteAddress() + "上线了~~~~");
            } else if (selectionKey.isReadable()) {
                readData(selectionKey);
            }
            // 移除，防止重复操作
            keyIterator.remove();
        }

    }

    /**
     * 读取客户端消息
     *
     * @param selectionKey
     */
    private void readData(SelectionKey selectionKey) {

        SocketChannel channel = null;

        try {
            // 得到SocketChannel
            channel = (SocketChannel) selectionKey.channel();
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            // 使用ByteBuffer接收
            int count = channel.read(buffer);
            if (count > 0) {
                // 从客户端接收到消息
                String msg = new String(buffer.array());
                System.out.println("从客户端接收：" + msg);
                // 转发
                sendInfoToOtherClients(msg, channel);
            }
        } catch (IOException e) {
            try {
                System.out.println(channel.getRemoteAddress() + "离线了~~~~");
                // 取消注册
                selectionKey.cancel();
                // 关闭通道
                channel.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }

    /**
     * 给其他客户端发送消息
     *
     * @param msg          消息
     * @param self
     */
    private void sendInfoToOtherClients(String msg, SocketChannel self) throws IOException {

        System.out.println("服务器转发消息中~~~~");

        // 从selector中获取所有连接的客户端
        for (SelectionKey key : selector.keys()) {
            Channel channel = key.channel();
            // 排除自己
            if (channel instanceof SocketChannel && channel != self) {
                // 转型
                SocketChannel dest = (SocketChannel) channel;
                ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
                dest.write(buffer);
            }
        }

    }

    public static void main(String[] args) {

    }
}
